
// originally borrowed from Mike Taulty's blog...
//  http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2006/09/06/8846.aspx

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Serialization;
using System.Xml;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.IO;
using System.Workflow.Runtime;

using TextFlow.Activities;
using TextFlow.Engine;

using ExternalActivities;

namespace TextFlow.Designer
{
    public partial class MainForm : Form
    {
        private DesignSurface _designSurface;
        private IDesignerHost _designerHost;
        private TextFlowWorkflow _workflow;
        private string _lastTFDFile;

        public MainForm()
        {
            InitializeComponent();
        }
        private void Form1_Load( object sender, EventArgs e )
        {
            _designSurface = new DesignSurface();

            _designerHost = _designSurface.GetService( typeof( IDesignerHost ) ) as IDesignerHost;

            rtbEditor.Focus();
        }

        private void RefreshWorkflowDesigner()
        {
            ClearWorkflowDesigner();

            AddActivityToDesigner( _workflow );

            IRootDesigner rootDesigner = _designerHost.GetDesigner( _designerHost.RootComponent ) as IRootDesigner;

            WorkflowView view = rootDesigner.GetView( ViewTechnology.Default ) as WorkflowView;

            Debug.Assert( view != null );

            view.Dock = DockStyle.Fill;

            panel1.Controls.Add( view );
        }

        private void ClearWorkflowDesigner()
        {
            panel1.Controls.Clear();
        }

        private void ClearLanguageDesigner()
        {
            rtbEditor.Clear();
        }

        private void AddActivityToDesigner( Activity activity )
        {
            Debug.Assert( activity != null );
            Debug.Assert( _designerHost != null );

            _designerHost.Container.Add( activity );

            if ( activity is CompositeActivity )
            {
                foreach ( Activity child in ( activity as CompositeActivity ).Activities )
                {
                    AddActivityToDesigner( child );
                }
            }
        }

        private void textFlowDocumentToolStripMenuItem_Click( object sender, EventArgs e )
        {
            OpenFileDialog ofd = new OpenFileDialog();

            ofd.Title = "Open TextFlow Document";
            ofd.SupportMultiDottedExtensions = true;
            ofd.RestoreDirectory = true;
            ofd.Multiselect = false;
            ofd.Filter = "TextFlow documents (*.tfd)|*.tfd|Text files (*.txt)|*.txt|All files (*.*)|*.*";

            if ( ofd.ShowDialog() == DialogResult.OK )
            {
                rtbEditor.Text = File.ReadAllText( ofd.FileName );

                _lastTFDFile = ofd.FileName;

                ClearWorkflowDesigner();
            }
        }

        private void xOMLFileToolStripMenuItem_Click( object sender, EventArgs e )
        {
            OpenFileDialog ofd = new OpenFileDialog();

            ofd.Title = "Open Xoml workflow";
            ofd.SupportMultiDottedExtensions = true;
            ofd.RestoreDirectory = true;
            ofd.Multiselect = false;
            ofd.Filter = "Xoml files (*.xoml)|*.xoml|All files (*.*)|*.*";

            if ( ofd.ShowDialog() == DialogResult.OK )
            {
                using ( XmlReader reader = XmlReader.Create( ofd.FileName ) )
                {
                    _workflow = TextFlowSerializer.Deserialize( reader );

                    ClearLanguageDesigner();

                    RefreshWorkflowDesigner();
                }
            }
        }

        private void saveToolStripMenuItem_Click( object sender, EventArgs e )
        {
            if ( _lastTFDFile == null )
            {
                saveAsToolStripMenuItem_Click( this, EventArgs.Empty );
            }
            else
            {
                File.WriteAllText( _lastTFDFile, rtbEditor.Text );
            }
        }

        private void saveAsToolStripMenuItem_Click( object sender, EventArgs e )
        {
            SaveFileDialog sfd = new SaveFileDialog();

            sfd.Title = "Save TextFlow document As...";
            sfd.SupportMultiDottedExtensions = true;
            sfd.RestoreDirectory = true;
            sfd.AddExtension = true;
            sfd.AutoUpgradeEnabled = true;
            sfd.DefaultExt = "tfd";
            sfd.Filter = "TextFlow document (*.tfd)|*.tfd|Text file (*.txt)|*.txt";

            if ( sfd.ShowDialog() == DialogResult.OK )
            {
                File.WriteAllText( sfd.FileName, rtbEditor.Text );
            }
        }

        private void exitToolStripMenuItem_Click( object sender, EventArgs e )
        {
            this.Close();
        }

        private void languageWorkflowToolStripMenuItem_Click( object sender, EventArgs e )
        {
            try
            {
                _workflow = TextFlowCompiler.Compile( rtbEditor.Text );

                Debug.Assert( _workflow != null );

                RefreshWorkflowDesigner();
            }
            catch ( Exception ex )
            {
                MessageBox.Show( ex.Message );
            }
        }

        private void workflowLanguageToolStripMenuItem_Click( object sender, EventArgs e )
        {
            Debug.Assert( _workflow != null );

            try
            {
                rtbEditor.Text = TextFlowDecompiler.Decompile( _workflow );
            }
            catch ( Exception ex )
            {
                MessageBox.Show( ex.Message );
            }
        }

        private void runWorkflowToolStripMenuItem_Click( object sender, EventArgs e )
        {
            try
            {
                string input = rtbEditor.Text;

                AppDomain isolated = AppDomain.CreateDomain( "TextFlow.Designer.Isolated" );

                try
                {
                    // MS *still* hasn't fixed the stupid bug where synthesized classes for C# anonymous
                    //  methods are not marked [Serializable]... bah

                    CrossADWork xAD = new CrossADWork( rtbEditor.Text );

                    isolated.DoCallBack( xAD.DoWork );
                }
                finally
                {
                    AppDomain.Unload( isolated );
                }
            }
            catch ( Exception ex )
            {
                MessageBox.Show( ex.Message );
            }
        }

        [Serializable]
        private class CrossADWork
        {
            private string _languageText;

            public CrossADWork( string languageText )
            {
                _languageText = languageText;
            }

            public void DoWork()
            {
                TextFlowExecutor executor = new TextFlowExecutor();

                executor.WorkflowCompleted += delegate
                {
                    MessageBox.Show( "Workflow done!" );
                };

                executor.WorkflowTerminated += delegate( object s, WorkflowTerminatedEventArgs arg )
                {
                    MessageBox.Show( arg.Exception.Message, "Workflow error", MessageBoxButtons.OK, MessageBoxIcon.Error );
                };

                executor.WorkflowSuspended += delegate( object sender, WorkflowSuspendedEventArgs arg )
                {
                    if ( arg.Error.StartsWith( "__internalsuspend:" ) )
                    {
                        MessageBox.Show( "Workflow suspended." );
                    }
                };

                executor.AddAssembly( typeof( MessageIOActivity ).Assembly );

                executor.AddService( new SuperSecretComputationService() );
                executor.AddService( new SomeTransactionalService() );
                executor.AddService( new InMemoryPersistenceService() );

                executor.Execute( _languageText );
            }
        }
    }
}
